package com.example.arve;

import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.client.android.PlanarYUVLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;

import android.support.v7.app.ActionBarActivity;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.media.AudioManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import android.os.Build;

/**
 * Description:
 * This is the display for the camera activity. It allows us to take photos and the like.
 * 
 * What's working: 
 * - Camera preview is fine
 * - You can take photos without any hassle
 * - Images are saved to the SD card (This is just for testing purposes to make sure images are coming through correctly)
 * What's not:
 * - QR decoding: same issue as QRActivity's decoding mechanism.
 * - Have yet to implement the switching of cameras, so the switch camera button does nothing at this current time
 * @author Richard
 *
 */
public class CameraActivity extends ActionBarActivity 
{	
	//The camera we're using
	private Camera active_camera;
	//What the camera can see
	private CameraSurface camera_display;
	
	//Our QR decoder
	Reader mfr = new QRCodeReader();
	//And the hints we want to give it
	Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_camera);

		// Create an instance of Camera
        active_camera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        camera_display = new CameraSurface(this, active_camera);
       
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(camera_display);
        
        //Will look harder for a barcode; takes a little longer though
      	hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
      	//We should look for QR codes
      	hints.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);
		
        //This is for fragments; I'll probably throw those in once I've worked out how to get them to not
        //want to kill the entire program
		/*if (savedInstanceState == null) {
			getSupportFragmentManager().beginTransaction()
					.add(R.id.container, new PlaceholderFragment()).commit();
		}*/
	}
	
	/**
	 * Auto-focus, then take the picture. Without auto focus, we're super blurry
	 * @param _view Just the current view
	 */
	public void takePhoto(View _view)
	{
		//Actually take the picture
		active_camera.autoFocus(new Camera.AutoFocusCallback() 
		{
	        @Override
	        public void onAutoFocus(boolean _success, Camera _camera) 
	        {
	            if(_success) //First we call auto focus. If we succeed, then take the photo, otherwise we get blurry photos
	            	active_camera.takePicture(play_shuttersound, null, take_photo);
	        }
	    });
		
	}
	
	/**
	 * Meant to swap from one camera to the next; don't have it working yet
	 * @param _view
	 */
	public void swapCamera(View _view)
	{
		
	}
	
	private PictureCallback take_photo = new PictureCallback()
	{
    	@Override 
    	public void onPictureTaken(byte[] _data, Camera _camera)
    	{
    		//Get the file we want to use
    		File picture_file = FileUri.createImageFile();//getOutputMediaFile(TYPE_IMG);
    		if(picture_file == null)
    		{
    			Log.e("MainCamActivity take_photo", "Couldn't create image file.");
    			return;
    		}
    		
    		//Reset our camera so we can take more photos
    		camera_display.resetCamera();
    		
    		FileOutputStream fos = null;
    		try
    		{
    			//Store our picture somewhere
    			fos = new FileOutputStream(picture_file);
    			fos.write(luminanceFromImage(_data).getMatrix());
    			fos.close();
    		}
    		catch(Exception _error)
    		{
    			Log.e("MainCamActivity take_photo2", "Couldn't save the picture.");
    		}
    		finally
    		{
    			if(fos != null)
    				try
    				{
    					fos.close();
    				}
    				catch(Exception _error)
    				{
    					
    				}
    		}
    		
    		readQRCodeFromImage(luminanceFromImage(_data));
    		
    		try
    		{
    			//if(picture_file != null)
    				//picture_file.delete(); //Just get rid of the picture once we've read the QR code
    		}
    		catch(Exception _error)
    		{
    			Log.e("MainCamActivity take_photo", "Couldn't delete the picture file.");
    		}
    	}
	};
	
	/**
	 * Meant to read from the luminance source to find the QR code
	 * Doesn't quite work yet; getting there slowly but surely
	 * @param _src The image that we converted into a YUV luminance source (YUV because android camera)
	 */
	private void readQRCodeFromImage(PlanarYUVLuminanceSource _src)
	{
		//Our result
		Result res = null;
		BinaryBitmap bmp = new BinaryBitmap(new HybridBinarizer(_src));
		try
		{
			//Here's to attempting to decode the code from the image
			res = mfr.decode(bmp, hints);
			//Just something to show if we actually found the QR code or not
			Toast.makeText(this, res.getText(), Toast.LENGTH_LONG).show();
		}
		catch(Exception _error)
		{
			//We just can't find it if we end up here
			Toast.makeText(this, "Couldn't find QR Code", Toast.LENGTH_LONG).show();
			Log.e("readQRCodeFromImage", _error.getMessage() + ": " + _error.toString());
		}
	}
	
	/**
	 * Placeholder function; just trying to get the QR code reading to work; will demolish soon
	 * @param _data The data of the picture we took
	 * @return A YUVLuminance source so we can read from it with the QR decoder
	 */
	private PlanarYUVLuminanceSource luminanceFromImage(byte[] _data)
	{	
		int scale = 4; 
		//Bitmap bmp = BitmapFactory.decodeFile(_file.getAbsolutePath());
		return new PlanarYUVLuminanceSource(_data, 640 / scale, 480 / scale, 0, 0, 640 / scale, 480 / scale, false);
		//return new PlanarYUVLuminanceSource(_data, camera_display.getFrameRect().width(), camera_display.getFrameRect().height(), 0, 0, camera_display.getFrameRect().width(), camera_display.getFrameRect().height(), false);
	}
	
	private ShutterCallback play_shuttersound = new ShutterCallback()
	{
		public void onShutter()
		{
			//Get our audio manager
			AudioManager audio = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
			//And play the shutter sound
			audio.playSoundEffect(AudioManager.FLAG_PLAY_SOUND);
		}
	};
	
	/**
	 * Just grabbing a camera. We wrap with try-catch since opening the camera may freak out if the camera is already in use
	 * @return An open camera if we succeeded, null if the camera is already being accessed.
	 */
	private Camera getCameraInstance()
    {
    	Camera c = null; 
    	try
    	{
    		//Attempt to open our camera
    		c = Camera.open(0);
    	}
    	catch(Exception _error)
    	{
    		Log.e("MainCamActivity getCameraInstance", "Couldn't retrieve an instance of a camera");
    	}
    	
    	return c;
    }

	@Override
	public boolean onCreateOptionsMenu(Menu menu) 
	{

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.camera, menu);
		return true;
	}
	
	@Override
	public void onResume()
	{
		super.onResume();
		if(active_camera == null) //If we don't have our camera, grab one
			active_camera = getCameraInstance();
		
		camera_display.takeCameraRef(active_camera); //And setup our preview once more
		camera_display.resetCamera();
		
	}
	
	@Override
    public void onPause()
    {
    	super.onPause();
    	//releaseCamera();
    }
	
	@Override
	public void onStop()
	{
		super.onStop();
		releaseCamera();
	}
	
	private void releaseCamera()
    {
		//If we have an instance of the camera
    	if(active_camera != null)
    	{
    		//Release the camera lock
    		active_camera.release();
    		//And set it to null
    		active_camera = null;
    	}
    }

	@Override
	public boolean onOptionsItemSelected(MenuItem item) 
	{
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	/**
	 * A placeholder fragment containing a simple view.
	 */
	/*
	public static class PlaceholderFragment extends Fragment 
	{

		public PlaceholderFragment() {
		}

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			View rootView = inflater.inflate(R.layout.fragment_camera,
					container, false);
			return rootView;
		}
	}*/

}
